package com.dylan.array;

import java.util.HashMap;
import java.util.Map;

/***
 *给定一个整数数组 nums 和一个目标值 target，请你在该数组中找出和为目标值的那 两个 整数，并返回他们的数组下标。
 *
 * 你可以假设每种输入只会对应一个答案。但是，数组中同一个元素不能使用两遍。
 *
 * 示例:
 *
 * 给定 nums = [2, 7, 11, 15], target = 9
 *
 * 因为 nums[0] + nums[1] = 2 + 7 = 9
 * 所以返回 [0, 1]
 */

public class TwoSum {

    /*** 暴力法： 两层遍历
     * 时间复杂度：O(n^2)
     *对于每个元素，我们试图通过遍历数组的其余部分来寻找它所对应的目标元素，这将耗费 O(n) 的时间。因此时间复杂度为 O(n^2)
     * 空间复杂度：O(1)
     */


    public int[] twoSum1(int[] nums, int target) {
        for (int i = 0; i < nums.length; i++) {
            for (int j = i+1; j < nums.length; j++) {
                if (nums[j] == target-nums[i]){
                    return new int[]{i,j};
                }
            }
        }
        throw new IllegalArgumentException("No two sum solution");
    }

    /*** 两遍哈希表
     * 为了对运行时间复杂度进行优化，我们需要一种更有效的方法来检查数组中是否存在目标元素。如果存在，我们需要找出它的索引。保持数组中的每个元素与其索引相互对应的最好方法是什么？哈希表。
     *
     *  时间复杂度：O(n)，
     * 我们把包含有 n 个元素的列表遍历两次。由于哈希表将查找时间缩短到 O(1) ，所以时间复杂度为 O(n)。
     *
     *空间复杂度：O(n)，
     * 所需的额外空间取决于哈希表中存储的元素数量，该表中存储了 n 个元素。
     * **/
    public int[] twoSum2(int[] nums, int target) {
        Map<Integer,Integer> tempMap = new HashMap<Integer,Integer>();
        for (int i = 0; i < nums.length; i++) {
            // 注意此处的key 和 value 正好颠倒了，为了下一个for更方便， 这是一个巧妙之处
            tempMap.put(nums[i],i);
        }
        for (int i = 0; i < nums.length; i++) {
            Integer digit = target-nums[i];
            if (tempMap.containsKey(digit) && tempMap.get(digit)!=i){
                return new int[]{i,tempMap.get(digit)};
            }
        }
        throw new IllegalArgumentException("No two sum solution");
    }

    /***  一遍哈希表
     *事实证明，我们可以一次完成。在进行迭代并将元素插入到表中的同时，我们还会回过头来检查表中是否已经存在当前元素所对应的目标元素。如果它存在，那我们已经找到了对应解，并立即将其返回。
     *
     *时间复杂度：O(n)，
     * 我们只遍历了包含有 n 个元素的列表一次。在表中进行的每次查找只花费 O(1) 的时间。
     *空间复杂度：O(n)，
     * 所需的额外空间取决于哈希表中存储的元素数量，该表最多需要存储 n 个元素。
     * */
    public int[] twoSum3(int[] nums, int target) {
        Map<Integer,Integer> tempMap = new HashMap<Integer,Integer>();
        for (int i = 0; i < nums.length; i++) {
            int digit = target - nums[i];
            if (tempMap.containsKey(digit)) {
                return new int[]{i, tempMap.get(digit)};
            }
            tempMap.put(nums[i],i);
        }
        throw new IllegalArgumentException("No two sum solution");
    }


}
